package internal

import (
	"context"
	"flag"
	"github.com/gin-gonic/gin"
	"github.com/morgine/log"
	"github.com/morgine/pkg/config"
	"github.com/morgine/pkg/database/orm"
	"github.com/morgine/pkg/redis"
	"github.com/morgine/redirect/internal/http/handlers"
	"github.com/morgine/redirect/internal/http/routes"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func Run() {
	// 加载配置文件
	configFile := flag.String("c", "config.toml", "配置文件")
	addr := flag.String("a", ":9879", "监听地址")
	flag.Parse()

	// 初始化配置服务
	var configs, err = config.UnmarshalFile(*configFile)
	if err != nil {
		panic(err)
	}
	gormDB, err := orm.NewPostgresORM("postgres", "gorm", configs)
	if err != nil {
		panic(err)
	}
	redisDB, err := redis.NewClient("redis", configs)
	if err != nil {
		panic(err)
	}

	engine, cancel := routes.Register(&routes.Options{
		Redis:       redisDB,
		DB:          gormDB,
		AuthExpires: 86400,
		AesCryptKey: "change this pass",
		DefaultAccounts: []handlers.AdminAccount{
			{Username: "sususu", Password: "popopo"},
			{Username: "mumumu", Password: "nonono"},
		},
	})
	defer func() {
		cancel()
		redisDB.Close()
		db, err := gormDB.DB()
		if err != nil {
			db.Close()
		}
	}()
	serveHttp(*addr, engine)
}

func serveHttp(addr string, engine *gin.Engine) {
	// 开启服务
	srv := &http.Server{
		Addr:         addr,
		Handler:      engine,
		ReadTimeout:  180 * time.Second,
		WriteTimeout: 180 * time.Second,
	}
	// Wait for interrupt signal to gracefully shutdown the server with
	// a timeout of 5 seconds.
	quit := make(chan os.Signal)

	// Initializing the server in a goroutine so that
	// it won't block the graceful shutdown handling below
	go func() {
		log.Init.Printf("listen and serve: http://localhost%s\n", addr)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Emergency.Printf("server stopped: %s\n", err)
			quit <- syscall.SIGINT
		}
	}()

	// kill (no param) default send syscall.SIGTERM
	// kill -2 is syscall.SIGINT
	// kill -9 is syscall.SIGKILL but can't be catch, so don't need add it
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	<-quit
	log.Init.Println("shutting down server...")

	// The context is used to inform the server it has 5 seconds to finish
	// the request it is currently handling
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Init.Println("server forced to shutdown:", err)
	}
	log.Init.Println("done!")
}
